<!DOCTYPE html>












  


<html class="theme-next gemini use-motion" lang="zh-CN">
<head><meta name="generator" content="Hexo 3.9.0">
  <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">












<meta http-equiv="Cache-Control" content="no-transform">
<meta http-equiv="Cache-Control" content="no-siteapp">






















<link href="/blog/lib/font-awesome/css/font-awesome.min.css?v=4.7.0" rel="stylesheet" type="text/css">

<link href="/blog/css/main.css?v=6.4.2" rel="stylesheet" type="text/css">


  <link rel="apple-touch-icon" sizes="180x180" href="/blog/images/apple-touch-icon-next.png?v=6.4.2">


  <link rel="icon" type="image/png" sizes="32x32" href="/blog/images/favicon-32x32-next.png?v=6.4.2">


  <link rel="icon" type="image/png" sizes="16x16" href="/blog/images/favicon-16x16-next.png?v=6.4.2">


  <link rel="mask-icon" href="/blog/images/logo.svg?v=6.4.2" color="#222">









<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/blog/',
    scheme: 'Gemini',
    version: '6.4.2',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: false,
    fastclick: false,
    lazyload: false,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>


  




  <meta name="description" content="主要内容有前端工程化，模块化，开发框架等。">
<meta name="keywords" content="前端进阶">
<meta property="og:type" content="article">
<meta property="og:title" content="Web前端进阶">
<meta property="og:url" content="https://xit-edu.cn/2018/11/03/blog/web-front-end-advance/web-front-end-advance/index.html">
<meta property="og:site_name" content="厦门工学院">
<meta property="og:description" content="主要内容有前端工程化，模块化，开发框架等。">
<meta property="og:locale" content="zh-CN">
<meta property="og:image" content="https://xit-edu.cn/2018/11/03/blog/web-front-end-advance/web-front-end-advance/react-life-cycle.png">
<meta property="og:image" content="https://xit-edu.cn/2018/11/03/blog/web-front-end-advance/web-front-end-advance/lifecycle.png">
<meta property="og:image" content="https://xit-edu.cn/2018/11/03/blog/web-front-end-advance/web-front-end-advance/lifecycle1.jpg">
<meta property="og:image" content="https://xit-edu.cn/2018/11/03/blog/web-front-end-advance/web-front-end-advance/lifecycle2.jpg">
<meta property="og:image" content="https://xit-edu.cn/2018/11/03/blog/web-front-end-advance/web-front-end-advance/未开启modules.png">
<meta property="og:image" content="https://xit-edu.cn/2018/11/03/blog/web-front-end-advance/web-front-end-advance/开启modules.png">
<meta property="og:image" content="https://xit-edu.cn/2018/11/03/blog/web-front-end-advance/web-front-end-advance/获取ip.png">
<meta property="og:image" content="https://xit-edu.cn/2018/11/03/blog/web-front-end-advance/web-front-end-advance/presets没有设置stage-2.png">
<meta property="og:image" content="https://xit-edu.cn/2018/11/03/blog/web-front-end-advance/web-front-end-advance/未装propTypes报错1.png">
<meta property="og:image" content="https://xit-edu.cn/2018/11/03/blog/web-front-end-advance/web-front-end-advance/未装propTypes报错2.png">
<meta property="og:image" content="https://xit-edu.cn/2018/11/03/blog/web-front-end-advance/web-front-end-advance/未exclude导致的babel报错.png">
<meta property="og:updated_time" content="2022-09-06T07:53:58.084Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Web前端进阶">
<meta name="twitter:description" content="主要内容有前端工程化，模块化，开发框架等。">
<meta name="twitter:image" content="https://xit-edu.cn/2018/11/03/blog/web-front-end-advance/web-front-end-advance/react-life-cycle.png">






  <link rel="canonical" href="https://xit-edu.cn/2018/11/03/blog/web-front-end-advance/web-front-end-advance/">



<script type="text/javascript" id="page.configurations">
  CONFIG.page = {
    sidebar: "",
  };
</script>

  <title>Web前端进阶 | 厦门工学院</title>
  






  <script type="text/javascript">
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?d3f181d3d99fc3c240567d5b682eebd1";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>






  <noscript>
  <style type="text/css">
    .use-motion .motion-element,
    .use-motion .brand,
    .use-motion .menu-item,
    .sidebar-inner,
    .use-motion .post-block,
    .use-motion .pagination,
    .use-motion .comments,
    .use-motion .post-header,
    .use-motion .post-body,
    .use-motion .collection-title { opacity: initial; }

    .use-motion .logo,
    .use-motion .site-title,
    .use-motion .site-subtitle {
      opacity: initial;
      top: initial;
    }

    .use-motion {
      .logo-line-before i { left: initial; }
      .logo-line-after i { right: initial; }
    }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-CN">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/blog/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">厦门工学院</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
    
      
        <p class="site-subtitle">软件研发工作室</p>
      
    
  </div>

  <div class="site-nav-toggle">
    <button aria-label="切换导航栏">
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>



<nav class="site-nav">
  
    <ul id="menu" class="menu">
      
        
        
        
          
          <li class="menu-item menu-item-home">
    <a href="/blog/" rel="section">
      <i class="menu-item-icon fa fa-fw fa-home"></i> <br>首页</a>
  </li>
        
        
        
          
          <li class="menu-item menu-item-archives">
    <a href="/blog/archives/" rel="section">
      <i class="menu-item-icon fa fa-fw fa-archive"></i> <br>归档</a>
  </li>
        
        
        
          
          <li class="menu-item menu-item-tags">
    <a href="/blog/tags/" rel="section">
      <i class="menu-item-icon fa fa-fw fa-tags"></i> <br>标签</a>
  </li>
        
        
        
          
          <li class="menu-item menu-item-categories">
    <a href="/blog/categories/" rel="section">
      <i class="menu-item-icon fa fa-fw fa-th"></i> <br>分类</a>
  </li>
        
        
        
          
          <li class="menu-item menu-item-works1">
    <a href="/blog/works1/" rel="section">
      <i class="menu-item-icon fa fa-fw fa-sitemap"></i> <br>H5小游戏1</a>
  </li>
        
        
        
          
          <li class="menu-item menu-item-works2">
    <a href="/blog/works2/" rel="section">
      <i class="menu-item-icon fa fa-fw fa-calendar"></i> <br>H5小游戏2</a>
  </li>
        
        
        
          
          <li class="menu-item menu-item-fiction">
    <a href="/blog/fiction/" rel="section">
      <i class="menu-item-icon fa fa-fw fa-heartbeat"></i> <br>大将军归来</a>
  </li>
        
        
        
          
          <li class="menu-item menu-item-about">
    <a href="/blog/about/" rel="section">
      <i class="menu-item-icon fa fa-fw fa-user"></i> <br>关于</a>
  </li>

      
      
    </ul>
  

  

  
</nav>



  



</div>
    </header>

    


    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          
            

          
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://xit-edu.cn/blog/2018/11/03/blog/web-front-end-advance/web-front-end-advance/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="对美好事物的向往，心中要充满强烈的愿望！">
      <meta itemprop="description" content="沉淀下来的知识，才是真正的财富！">
      <meta itemprop="image" content="/blog/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="厦门工学院">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">Web前端进阶
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">

            
            
            

            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              

              
                
              

              <time title="创建时间：2018-11-03 12:00:00" itemprop="dateCreated datePublished" datetime="2018-11-03T12:00:00+08:00">2018-11-03</time>
            

            
              

              
                
                <span class="post-meta-divider">|</span>
                

                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                
                  <span class="post-meta-item-text">更新于</span>
                
                <time title="修改时间：2022-09-06 15:53:58" itemprop="dateModified" datetime="2022-09-06T15:53:58+08:00">2022-09-06</time>
              
            
          </span>

          
            <span class="post-category">
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/blog/categories/WEB前端/" itemprop="url" rel="index"><span itemprop="name">WEB前端</span></a></span>

                
                
                  ，
                
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/blog/categories/WEB前端/前端进阶/" itemprop="url" rel="index"><span itemprop="name">前端进阶</span></a></span>

                
                
              
            </span>
          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p>主要内容有前端工程化，模块化，开发框架等。</p>
<a id="more"></a>
<h2 id="前端框架"><a href="#前端框架" class="headerlink" title="前端框架"></a>前端框架</h2><h3 id="React生命周期"><a href="#React生命周期" class="headerlink" title="React生命周期"></a>React生命周期</h3><p>对react的生命周期的前世今生要能了解清楚。</p>
<ul>
<li>了解15.6 16.0 16.3几个关键版本的变化</li>
<li>fiber解决了什么问题</li>
<li>为什么说willMount，willUpdate，willReceive等方法是不安全的</li>
</ul>
<p><img src="react-life-cycle.png"></p>
<p><img src="lifecycle.png"></p>
<p><img src="lifecycle1.jpg"></p>
<p><img src="lifecycle2.jpg"></p>
<h3 id="Redux-Saga"><a href="#Redux-Saga" class="headerlink" title="Redux Saga"></a>Redux Saga</h3><p>saga执行流程。<br>当我dispatch一个action后，这个先发到reducer。然后才走到saga，saga拿到后put了一个新的action这个新的action才是我们要处理的。</p>
<p>简单来说，当我们dispatch一个action后，先发到reducer，然后saga同时也收到了一份，这时候saga可以put出新的action给reducer接收。</p>
<p>换句话来说，saga是监听redux总线上的数据，原来怎么dispatch还是按照原来的走，当saga监听到action后可以自己做一些处理然后put出新的action。</p>
<p>循环事件。<br>后来的事件把前面的覆盖<code>takeLast</code></p>
<p>并发请求。<br>有时候有些操作需要发起多个请求，这样一个操作的时间就需要time1+time2+time3。但是，如果这些请求没有先后关系就可以一次性发出请求，这样做的好处就是这个操作的时间只会是最长的那个请求的时间。比如原来的时间是100ms+200ms+150ms，现在就只要200ms。<code>yield call(api1,api2,api3)</code></p>
<p>顺序执行和并行执行。<br>在saga中有些操作需要互相调用方法。<code>yield put(action1)</code>是异步的，<code>yield* sagaFun1()</code>同步的。可以根据实际情况结合使用。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 并发执行，put完action1，不用等action1返回，就接着put action2。</span></span><br><span class="line"><span class="keyword">yield</span> put(action1)</span><br><span class="line"><span class="keyword">yield</span> put(action2)</span><br><span class="line"><span class="keyword">yield</span> put(action3)</span><br><span class="line"><span class="comment">// 顺序执行，执行完sagaFun1，才会执行sagaFun2。</span></span><br><span class="line"><span class="keyword">yield</span>* sagaFun1()</span><br><span class="line"><span class="keyword">yield</span>* sagaFun2()</span><br><span class="line"><span class="keyword">yield</span>* sagaFun3()</span><br></pre></td></tr></table></figure>
<h3 id="Immutable"><a href="#Immutable" class="headerlink" title="Immutable"></a>Immutable</h3><h4 id="基本规范"><a href="#基本规范" class="headerlink" title="基本规范"></a>基本规范</h4><p>state.set(‘key’,value)</p>
<p>如果value是基础类型，比如number，string等，是可以直接这样set进去。</p>
<p>如果value是对象类型，比如map，list等，可以fromJS(value)再设置进去。</p>
<p>因为<code>state.set(&#39;key&#39;,fromJS(1))</code>和<code>state.set(&#39;key&#39;,1)</code>，在<code>state.get(&#39;key&#39;)</code>是一样的。但是，<code>state.set(&#39;key&#39;,fromJS({a:1}))</code>和<code>state.set(&#39;key&#39;,{a:1})</code>，在<code>state.get(&#39;key&#39;)</code>是不一样的。前者get出来的是一个immutable对象，后者get出来的是一个js对象。</p>
<p>所以综上所述，在set的时候，如果是基础类型可以直接set，如果是对象类型要先<code>fromJS()</code>再set进去。</p>
<p>以此类推<code>state.merge({&#39;key2&#39;,value2})</code>这个value也是一样的道理。</p>
<h4 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h4><p>不要在container里面toJS()，因为toJS()之后会是一个新的对象，会导致react重新render。</p>
<p>可以配合<code>with-immutable-props-to-js</code>使用<code>const TodoListSmart = connect(mapStateToProps,mapDispatchToProps)(WithImmutablePropsToJs(TodoListDump))</code>。这样可以保证<code>TodoListDump</code>获取到的props<code>如果是同一个值不会产生新的对象</code>。</p>
<h2 id="Webpack"><a href="#Webpack" class="headerlink" title="Webpack"></a>Webpack</h2><h3 id="基本思想"><a href="#基本思想" class="headerlink" title="基本思想"></a>基本思想</h3><h4 id="Loader"><a href="#Loader" class="headerlink" title="Loader"></a>Loader</h4><p>Loader 就是将 Webpack 不认识的内容转化为认识的内容。</p>
<p>webpack 默认支持处理 JS 与 JSON 文件，其他类型都处理不了，这里必须借助 Loader 来对不同类型的文件的进行处理。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> config = &#123;</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">  <span class="built_in">module</span>: &#123; </span><br><span class="line">    rules: [</span><br><span class="line">      &#123;</span><br><span class="line">        test: <span class="regexp">/\.css$/</span>, <span class="comment">//匹配所有的 css 文件</span></span><br><span class="line">        use: [<span class="string">'style-loader'</span>,<span class="string">'css-loader'</span>]</span><br><span class="line">        <span class="comment">//⚠️注意： Loader 的执行顺序是固定从后往前，即按 css-loader --&gt; style-loader 的顺序执行。</span></span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="css-loader"><a href="#css-loader" class="headerlink" title="css-loader"></a>css-loader</h5><p>css-loader把css文件进行转换后生成字符串，并用eval的方式，实现其具体作用。</p>
<p>eval() 函数计算 JavaScript 字符串，并把它作为脚本代码来执行。如果参数是一个表达式，eval() 函数将执行表达式。如果参数是Javascript语句，eval()将执行 Javascript 语句。</p>
<h5 id="style-loader"><a href="#style-loader" class="headerlink" title="style-loader"></a>style-loader</h5><p>style-loader 就是将处理好的 css 通过 style 标签的形式添加到页面上</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> content = <span class="string">`<span class="subst">$&#123;样式内容&#125;</span>`</span></span><br><span class="line"><span class="keyword">const</span> style = <span class="built_in">document</span>.createElement(<span class="string">'style'</span>);</span><br><span class="line">style.innerHTML = content;</span><br><span class="line"><span class="built_in">document</span>.head.appendChild(style);</span><br></pre></td></tr></table></figure>
<h4 id="Plugin"><a href="#Plugin" class="headerlink" title="Plugin"></a>Plugin</h4><p>与 Loader 用于转换特定类型的文件不同，插件（Plugin）可以贯穿Webpack 打包的生命周期，执行不同的任务。</p>
<h3 id="webpack5新特性"><a href="#webpack5新特性" class="headerlink" title="webpack5新特性"></a>webpack5新特性</h3><p>webpack5 新增资源模块(asset module)，允许使用资源文件（字体，图标等）而无需配置额外的 loader。</p>
<p>asset/resource 将资源分割为单独的文件，并导出 url，类似之前的 file-loader 的功能.<br>asset/inline 将资源导出为 dataUrl 的形式，类似之前的 url-loader 的小于 limit 参数时功能.<br>asset/source 将资源导出为源码（source code）. 类似的 raw-loader 功能.<br>asset 会根据文件大小来选择使用哪种类型，当文件小于 8 KB（默认） 的时候会使用 asset/inline，否则会使用 asset/resource</p>
<h3 id="打包流程"><a href="#打包流程" class="headerlink" title="打包流程"></a>打包流程</h3><p>webpack的整个打包流程：</p>
<p>1、读取webpack的配置参数；<br>2、启动webpack，创建Compiler对象并开始解析项目；<br>3、从入口文件（entry）开始解析，并且找到其导入的依赖模块，递归遍历分析，形成依赖关系树；<br>4、对不同文件类型的依赖模块文件使用对应的Loader进行编译，最终转为Javascript文件；<br>5、整个过程中webpack会通过发布订阅模式，向外抛出一些hooks，而webpack的插件即可通过监听这些关键的事件节点，执行插件任务进而达到干预输出结果的目的。</p>
<p>其中文件的解析与构建是一个比较复杂的过程，在webpack源码中主要依赖于compiler和compilation两个核心对象实现。<br>compiler对象是一个全局单例，他负责把控整个webpack打包的构建流程。<br>compilation对象是每一次构建的上下文对象，它包含了当次构建所需要的所有信息，每次热更新和重新构建，compiler都会重新生成一个新的compilation对象，负责此次更新的构建过程。<br>而每个模块间的依赖关系，则依赖于AST语法树。每个模块文件在通过Loader解析完成之后，会通过acorn库生成模块代码的AST语法树，通过语法树就可以分析这个模块是否还有依赖的模块，进而继续循环执行下一个模块的编译解析。<br>最终Webpack打包出来的bundle文件是一个IIFE的执行函数。</p>
<p>和webpack4相比，webpack5打包出来的bundle做了相当的精简。在上面的打包demo中，整个立即执行函数里边只有<code>三个变量</code>和<code>一个函数方法</code>，<code>__webpack_modules__</code>存放了编译后的各个文件模块的JS内容，<code>__webpack_module_cache__</code> 用来做模块缓存，<code>__webpack_require__</code>是Webpack内部实现的一套依赖引入函数。最后一句则是代码运行的起点，从入口文件开始，启动整个项目。<br>其中值得一提的是<code>__webpack_require__</code>模块引入函数，我们在模块化开发的时候，通常会使用ES Module或者CommonJS规范导出/引入依赖模块，webpack打包编译的时候，会统一替换成自己的<code>__webpack_require__</code>来实现模块的引入和导出，从而实现模块缓存机制，以及抹平不同模块规范之间的一些差异性。</p>
<h3 id="devtool"><a href="#devtool" class="headerlink" title="devtool"></a>devtool</h3><p>1、source-map <code>会</code>生成map格式的文件，里面<code>包含</code>映射关系的代码。<br>2、inline-source-map <code>不会</code>生成map格式的文件，<code>包含</code>映射关系的代码会放在打包后生成的代码中<br>3、inline-cheap-source-map cheap有两种作用：一是将错误只定位到行，不定位到列。二是映射业务代码，不映射loader和第三方库等。会提升打包构建的速度。<br>4、inline-cheap-module-source-map module会映射loader和第三方库<br>5、eval 用eval的方式生成映射关系代码，效率和性能最佳。但是当代码复杂时，提示信息可能不精确。</p>
<p>提到sourceMap，很多小伙伴可能会立刻想到Webpack配置里边的devtool参数，以及对应的eval，eval-cheap-source-map等等可选值以及它们的含义。除了知道不同参数之间的区别以及性能上的差异外，我们也可以一起了解一下sourceMap的实现方式。</p>
<p>sourceMap是一项将编译、打包、压缩后的代码映射回源代码的技术，由于打包压缩后的代码并没有阅读性可言，一旦在开发中报错或者遇到问题，直接在混淆代码中debug问题会带来非常糟糕的体验，sourceMap可以帮助我们快速定位到源代码的位置，提高我们的开发效率。</p>
<p>既然是一种源码的映射，那必然就需要有一份映射的文件，来标记混淆代码里对应的源码的位置，通常这份映射文件以.map结尾，里边的数据结构大概长这样：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="string">"version"</span> : <span class="number">3</span>,                          <span class="comment">// Source Map版本</span></span><br><span class="line">  <span class="string">"file"</span>: <span class="string">"out.js"</span>,                       <span class="comment">// 输出文件（可选）</span></span><br><span class="line">  <span class="string">"sourceRoot"</span>: <span class="string">""</span>,                       <span class="comment">// 源文件根目录（可选）</span></span><br><span class="line">  <span class="string">"sources"</span>: [<span class="string">"foo.js"</span>, <span class="string">"bar.js"</span>],        <span class="comment">// 源文件列表</span></span><br><span class="line">  <span class="string">"sourcesContent"</span>: [<span class="literal">null</span>, <span class="literal">null</span>],         <span class="comment">// 源内容列表（可选，和源文件列表顺序一致）</span></span><br><span class="line">  <span class="string">"names"</span>: [<span class="string">"src"</span>, <span class="string">"maps"</span>, <span class="string">"are"</span>, <span class="string">"fun"</span>], <span class="comment">// mappings使用的符号名称列表</span></span><br><span class="line">  <span class="string">"mappings"</span>: <span class="string">"A,AAAB;;ABCDE;"</span>            <span class="comment">// 带有编码映射数据的字符串</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>其中mappings数据有如下规则：</p>
<ul>
<li>生成文件中的一行的每个组用“;”分隔；</li>
<li>每一段用“,”分隔；</li>
<li>每个段由1、4或5个可变长度字段组成；</li>
</ul>
<p>有了这份映射文件，我们只需要在我们的压缩代码的最末端加上这句注释，即可让sourceMap生效：<br><code>//# sourceURL=/path/to/file.js.map</code><br>有了这段注释后，浏览器就会通过sourceURL去获取这份映射文件，通过解释器解析后，实现源码和混淆代码之间的映射。因此sourceMap其实也是一项需要浏览器支持的技术。<code>需要浏览器支持sourceURL</code>。<br>如果我们仔细查看webpack打包出来的bundle文件，就可以发现在默认的development开发模式下，每个<code>__webpack_modules__文</code>件模块的代码最末端，都会加上<code>//# sourceURL=webpack://file-path?</code>，从而实现对sourceMap的支持。</p>
<h3 id="model"><a href="#model" class="headerlink" title="model"></a>model</h3><p>mode可设置development production两个参数<br>如果没有设置，webpack4 会将 mode 的默认值设置为 production<br>production模式下会进行tree shaking(去除无用代码)和uglifyjs(代码压缩混淆)</p>
<h3 id="Three-shaking"><a href="#Three-shaking" class="headerlink" title="Three-shaking"></a>Three-shaking</h3><p>这里单独提一下tree-shaking,是因为这里有个坑。tree-shaking的主要作用是用来清除代码中无用的部分。目前在webpack4 我们设置mode为production的时候已经自动开启了tree-shaking。但是要想使其生效，生成的代码必须是ES6模块。不能使用其它类型的模块如CommonJS之流。如果使用Babel的话，这里有一个小问题，因为Babel的预案（preset）默认会将任何模块类型都转译成CommonJS类型，这样会导致tree-shaking失效。修正这个问题也很简单，在.babelrc文件或在webpack.config.js文件中设置modules： false就好了</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// .babelrc</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">"presets"</span>: [</span><br><span class="line">    [<span class="string">"@babel/preset-env"</span>,</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="string">"modules"</span>: <span class="literal">false</span></span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// webpack.config.js</span></span><br><span class="line"><span class="built_in">module</span>: &#123;</span><br><span class="line">    rules: [</span><br><span class="line">        &#123;</span><br><span class="line">            test: <span class="regexp">/\.js$/</span>,</span><br><span class="line">            use: &#123;</span><br><span class="line">                loader: <span class="string">'babel-loader'</span>,</span><br><span class="line">                options: &#123;</span><br><span class="line">                    presets: [<span class="string">'@babel/preset-env'</span>, &#123; <span class="attr">modules</span>: <span class="literal">false</span> &#125;]</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;，</span><br><span class="line">            exclude: <span class="regexp">/(node_modules)/</span></span><br><span class="line">        &#125;</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="基本优化"><a href="#基本优化" class="headerlink" title="基本优化"></a>基本优化</h3><p>合并和拆分。合并业务代码，拆分公共代码。splitChunks<br>图片优化。雪碧图。url-loader和file-loader配合使用。limit8k的图通过file-loader直接打入css里面。超过8K的再用url-loader加载。可以和雪碧图综合考虑。<br>压缩js和css。UglifyJsPlugin，并置顶。、OptimizeCSSAssetsPlugin<br>样式表用link引入</p>
<h3 id="loader和plugin的区别"><a href="#loader和plugin的区别" class="headerlink" title="loader和plugin的区别"></a>loader和plugin的区别</h3><p>如果说Loader负责文件转换，那么Plugin便是负责功能扩展。</p>
<p>webpack最后打包出来的成果是一份Javascript代码，实际上在Webpack内部默认也只能够处理JS模块代码，在打包过程中，会默认把所有遇到的文件都当作 JavaScript代码进行解析，因此当项目存在非JS类型文件时，我们需要<code>使用loader先对其进行必要的转换</code>，才能继续执行打包任务。</p>
<p>webpack在运行的生命周期中会广播出许多事件，<code>使用插件plugin通过监听这些事件</code>，就可以在特定的阶段执行自己的插件任务，从而实现自己想要的功能。其中compiler暴露了和 Webpack整个生命周期相关的钩子（compiler-hooks），而compilation则暴露了与模块和依赖有关的粒度更小的事件钩子（Compilation Hooks）。</p>
<h4 id="loader"><a href="#loader" class="headerlink" title="loader"></a>loader</h4><p>Webpack最后打包出来的成果是一份Javascript代码，实际上在Webpack内部默认也只能够处理JS模块代码，在打包过程中，会默认把所有遇到的文件都当作 JavaScript代码进行解析，因此当项目存在非JS类型文件时，我们需要先对其进行必要的转换，才能继续执行打包任务，这也是Loader机制存在的意义。</p>
<p>针对每个文件类型，loader是支持以数组的形式配置多个的，因此当Webpack在转换该文件类型的时候，会按顺序链式调用每一个loader，前一个loader返回的内容会作为下一个loader的入参。因此loader的开发需要遵循一些规范，比如返回值必须是标准的JS代码字符串，以保证下一个loader能够正常工作，同时在开发上需要严格遵循“单一职责”，只关心loader的输出以及对应的输出。<br>loader函数中的this上下文由webpack提供，可以通过this对象提供的相关属性，获取当前loader需要的各种信息数据，事实上，这个this指向了一个叫loaderContext的loader-runner特有对象</p>
<h5 id="loader编写原则"><a href="#loader编写原则" class="headerlink" title="loader编写原则"></a>loader编写原则</h5><p>单一原则: 每个 Loader 只做一件事；<br>链式调用: Webpack 会按顺序链式调用每个 Loader；<br>统一原则: 遵循 Webpack 制定的设计规则和结构，输入与输出均为字符串，各个 Loader 完全独立，即插即用；</p>
<p>在日常开发环境中，为了方便调试我们往往会加入许多console打印。但是我们不希望在生产环境中存在打印的值。那么这里我们自己实现一个loader去除代码中的console</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// drop-console.js</span></span><br><span class="line"><span class="keyword">const</span> parser = <span class="built_in">require</span>(<span class="string">'@babel/parser'</span>)</span><br><span class="line"><span class="keyword">const</span> traverse = <span class="built_in">require</span>(<span class="string">'@babel/traverse'</span>).default</span><br><span class="line"><span class="keyword">const</span> generator = <span class="built_in">require</span>(<span class="string">'@babel/generator'</span>).default</span><br><span class="line"><span class="keyword">const</span> t = <span class="built_in">require</span>(<span class="string">'@babel/types'</span>)</span><br><span class="line"><span class="built_in">module</span>.exports=<span class="function"><span class="keyword">function</span>(<span class="params">source</span>)</span>&#123;</span><br><span class="line">  <span class="keyword">const</span> ast = parser.parse(source,&#123; <span class="attr">sourceType</span>: <span class="string">'module'</span>&#125;)<span class="comment">// 1.将源代码解析成 AST</span></span><br><span class="line">  traverse(ast,&#123;<span class="comment">// 2.对AST节点进行递归遍历，生成一个便于操作、转换的path对象</span></span><br><span class="line">    CallExpression(path)&#123; </span><br><span class="line">      <span class="comment">// 3.通过该模块对具体的AST节点进行进行增、删、改、查。对path对象进行操作。</span></span><br><span class="line">      <span class="keyword">if</span>(t.isMemberExpression(path.node.callee) &amp;&amp; t.isIdentifier(path.node.callee.object, &#123;<span class="attr">name</span>: <span class="string">"console"</span>&#125;))&#123;</span><br><span class="line">        path.remove()</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">  <span class="keyword">const</span> output = generator(ast, &#123;&#125;, source);<span class="comment">// 4.将AST解码生成js代码</span></span><br><span class="line">  <span class="keyword">return</span> output.code</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// webpack.conf.js</span></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>)</span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  mode:<span class="string">'development'</span>,</span><br><span class="line">  entry:path.resolve(__dirname,<span class="string">'index.js'</span>),</span><br><span class="line">  output:&#123;</span><br><span class="line">    filename:<span class="string">'[name].[contenthash].js'</span>,</span><br><span class="line">    path:path.resolve(__dirname,<span class="string">'dist'</span>)</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="built_in">module</span>:&#123;</span><br><span class="line">    rules:[&#123;</span><br><span class="line">      test:<span class="regexp">/\.js$/</span>,</span><br><span class="line">      use:path.resolve(__dirname,<span class="string">'drop-console.js'</span>)<span class="comment">// 自定义loader</span></span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="样式表的Loader-style-loader-css-loader-sass-loader"><a href="#样式表的Loader-style-loader-css-loader-sass-loader" class="headerlink" title="样式表的Loader style-loader css-loader sass-loader"></a>样式表的Loader style-loader css-loader sass-loader</h5><p>css-Loader把css通过<code>&lt;link/&gt;</code>引入，而style-loader把css放到<code>&lt;styles/&gt;</code>里面。<br>css-loader要配合MiniCssExtractPlugin.loader会把css进行抽取独立文件。<br>css-loader要启用modules=true，在代码里面才能import styles from ‘style.css’。才可以设置localIdentName规则，让css的名称唯一防止全名冲突。<br>可以开启OptimizeCSSAssetsPlugin对css进行压缩。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  test: <span class="regexp">/\.(sc|c)ss$/</span>,</span><br><span class="line">  use: [</span><br><span class="line">    MiniCssExtractPlugin.loader,</span><br><span class="line">    &#123;</span><br><span class="line">      loader: <span class="string">'css-loader'</span>,</span><br><span class="line">      options: &#123;</span><br><span class="line">        modules: <span class="literal">true</span>,</span><br><span class="line">        localIdentName: <span class="string">'[path][name]__[local]--[hash:base64:5]'</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      loader: <span class="string">'sass-loader'</span></span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="未开启modules.png"><br><img src="开启modules.png"></p>
<h5 id="file-loader与url-loader"><a href="#file-loader与url-loader" class="headerlink" title="file-loader与url-loader"></a>file-loader与url-loader</h5><p>相同点：都可以用来加载资源文件。<br>不同点：url-loader可以设置小于指定大小的文件直接打包到js里面，减少请求次数。file-loader则是把文件加载到指定目录。<br>当有文件超过<code>url-loader</code>指定的文件大小后，不会被打包到js里面，但是它就变成需要<code>file-loader</code>加载否则会报错。<br>把小图片打包到js里面减少请求次数各有利弊。优点：可以减少小图片的请求次数，降低网络IO的请求次数。缺点：图片会被转换成base64的格式和js一起打包进入会带出新的问题，就是这样会导致css变大，这样加载单个css可能需要的时长会更长。另外，base64的算法是把原来的数据每3位用4位替换，这样原来如果是1，就会变成4/3，相当于比原来大了1/3。<br>因此是否需要使用url-loader把小图片打包到js文件需要权衡后再做决定。把小图片打包到js需要做的牺牲就是js文件会变大。<br>file-loader实现的是懒加载，只有在页面需要用到具体的元素才会加载，否则并不会加载。这样能提高整体的性能。<br>file-loader的publicPath属性，用来指定访问的路径。<br>file-loader的outputPath属性，用来指定打包输出的路径和访问的路径。建议使用outputPath属性，因为这个属性同时指定了打包输入和访问的路径，而publicPath只指定了访问的路径，如果你实际打包的路径不是这个就访问不到了。<br>url-loader的limit属性，用来指定小于限定的字节(Byte)则打包到js文件里面，超过限定的字节(Byte)则需要file-loader加载。<br>基本用法如下，小于8k的图片可以转成base64一起打入css，大于的则用file-loader加载。这样既可以减少图片请求数，又保证了css文件不会太大。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  test:<span class="regexp">/\.(jpg|png|svg|gif)/</span>,</span><br><span class="line">  use:[&#123;</span><br><span class="line">    loader:<span class="string">'url-loader'</span>,</span><br><span class="line">    options:&#123;</span><br><span class="line">      limit:<span class="number">8129</span>,<span class="comment">//小于limit限制8k 的图片将转为base64嵌入引用位置</span></span><br><span class="line">      fallback:<span class="string">'file-loader'</span>,<span class="comment">//大于limit限制的将转交给指定的loader处理</span></span><br><span class="line">      outputPath:<span class="string">'imgs/'</span><span class="comment">//options会直接传给fallback指定的loader</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="plugin"><a href="#plugin" class="headerlink" title="plugin"></a>plugin</h4><p>如果说Loader负责文件转换，那么Plugin便是负责功能扩展。Loader和Plugin作为Webpack的两个重要组成部分，承担着两部分不同的职责。</p>
<p>webpack基于发布订阅模式，在运行的生命周期中会广播出许多事件，插件通过监听这些事件，就可以在特定的阶段执行自己的插件任务，从而实现自己想要的功能。</p>
<p>既然基于发布订阅模式，那么知道Webpack到底提供了哪些事件钩子供插件开发者使用是非常重要的，上文提到过compiler和compilation是Webpack两个非常核心的对象，其中compiler暴露了和 Webpack整个生命周期相关的钩子（compiler-hooks），而compilation则暴露了与模块和依赖有关的粒度更小的事件钩子（Compilation Hooks）。<br>Webpack的事件机制基于webpack自己实现的一套Tapable事件流方案（github）</p>
<h5 id="plugin编写原则"><a href="#plugin编写原则" class="headerlink" title="plugin编写原则"></a>plugin编写原则</h5><p>Plugin的开发和开发Loader一样，需要遵循一些开发上的规范和原则：</p>
<ul>
<li>插件必须是一个函数或者是一个包含 apply 方法的对象，这样才能访问compiler实例；</li>
<li>传给每个插件的 compiler 和 compilation 对象都是同一个引用，若在一个插件中修改了它们身上的属性，会影响后面的插件;</li>
<li>异步的事件需要在插件处理完任务时调用回调函数通知 Webpack 进入下一个流程，不然会卡住;</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">firstPlugin</span> </span>&#123;</span><br><span class="line">  <span class="keyword">constructor</span> (options) &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'firstPlugin options'</span>, options)</span><br><span class="line">  &#125;</span><br><span class="line">  apply (compiler) &#123;<span class="comment">//compiler包含了webpack整个生命周期</span></span><br><span class="line">    compiler.plugin(<span class="string">'done'</span>, compilation =&gt; &#123;<span class="comment">//在done阶段执行一下逻辑，compilation包含了这一阶段所需的阶段变量。</span></span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'firstPlugin'</span>)</span><br><span class="line">    ))</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = firstPlugin</span><br></pre></td></tr></table></figure>
<p>compiler 对象包含了Webpack 环境所有的的配置信息。这个对象在启动 webpack 时被一次性建立，并配置好所有可操作的设置，包括 options，loader 和 plugin。当在 webpack 环境中应用一个插件时，插件将收到此 compiler 对象的引用。可以使用它来访问 webpack 的主环境。</p>
<p>compilation对象包含了当前的模块资源、编译生成资源、变化的文件等。当运行webpack 开发环境中间件时，每当检测到一个文件变化，就会创建一个新的 compilation，从而生成一组新的编译资源。compilation 对象也提供了很多关键时机的回调，以供插件做自定义处理时选择使用。</p>
<p>compiler和 compilation的区别在于</p>
<ul>
<li>compiler代表了整个webpack从启动到关闭的生命周期，而compilation 只是代表了一次新的编译过程</li>
<li><p>compiler和compilation暴露出许多钩子，我们可以根据实际需求的场景进行自定义处理</p>
<p>compiler当处于监听模式(watch mode)时， compiler 会触发诸如 watchRun, watchClose 和 invalid 等额外的事件。 通常在 开发环境 中使用， 也常常会在 webpack-dev-server 这些工具的底层调用， 由此开发人员无须每次都使用手动方式重新编译。 还可以通过 CLI 进入监听模式。</p>
</li>
</ul>
<p>下面我们手动开发一个简单的需求,在生成打包文件之前自动生成一个关于打包出文件的大小信息</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// webpack-firstPlugin.js</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">firstPlugin</span></span>&#123;</span><br><span class="line">  <span class="keyword">constructor</span>(options)&#123;</span><br><span class="line">    <span class="keyword">this</span>.options = options</span><br><span class="line">  &#125;</span><br><span class="line">  apply(compiler)&#123;</span><br><span class="line">    compiler.plugin(<span class="string">'emit'</span>,(compilation,callback)=&gt;&#123;<span class="comment">//在emit阶段，生成文件名称和对应大小信息，写入fileSize.md文件里面。</span></span><br><span class="line">      <span class="keyword">let</span> str = <span class="string">''</span></span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> filename <span class="keyword">in</span> compilation.assets)&#123;</span><br><span class="line">        str += <span class="string">`文件:<span class="subst">$&#123;filename&#125;</span>  大小<span class="subst">$&#123;compilation.assets[filename][<span class="string">'size'</span>]()&#125;</span>\n`</span></span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">// 通过compilation.assets可以获取打包后静态资源信息，同样也可以写入资源</span></span><br><span class="line">      compilation.assets[<span class="string">'fileSize.md'</span>] = &#123;</span><br><span class="line">        source:<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">          <span class="keyword">return</span> str</span><br><span class="line">        &#125;,</span><br><span class="line">        size:<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">          <span class="keyword">return</span> str.length</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      callback()</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">module</span>.exports = firstPlugin</span><br><span class="line"></span><br><span class="line"><span class="comment">// webpack.conf.js</span></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>)</span><br><span class="line"><span class="keyword">const</span> firstPlugin = <span class="built_in">require</span>(<span class="string">'webpack-firstPlugin.js'</span>)</span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">    plugins:[</span><br><span class="line">        <span class="keyword">new</span> firstPlugin()</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="补充学习"><a href="#补充学习" class="headerlink" title="补充学习"></a>补充学习</h3><h4 id="dirname和process-cwd"><a href="#dirname和process-cwd" class="headerlink" title="__dirname和process.cwd()"></a><code>__dirname</code>和<code>process.cwd()</code></h4><p><code>__dirname</code>是当前js文件所处的路径。<br><code>process.cwd()</code>是当前进程的工作目录，参照package.json所在的位置的。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.info(<span class="string">'process.cwd()是当前进程的工作目录，参照package.json所在的位置的。'</span>,process.cwd())</span><br><span class="line"><span class="built_in">console</span>.info(<span class="string">'__dirname是当前js文件所处的路径。'</span>,__dirname)</span><br></pre></td></tr></table></figure>
<p>path<br>要使用<code>path</code>需要先<code>npm install path</code>，然后再在需要的文件里面引入<code>const path = require(&#39;path&#39;);</code>才可以使用。<br>两种用法<br>连接路径：<code>path.join([path1][, path2][, ...])</code><br>路径解析：<code>path.resolve([from ...], to)</code><br>最大的区别：就是对<code>/</code>的解析，<code>join</code>只是拼上去，而<code>resolve</code>则是解析成根路径<code>/</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>);</span><br><span class="line">path.join(<span class="string">'/foo'</span>, <span class="string">'bar'</span>, <span class="string">'baz/asdf'</span>, <span class="string">'quux'</span>, <span class="string">'..'</span>)<span class="comment">// 连接后'/foo/bar/baz/asdf'</span></span><br><span class="line">path.resolve(<span class="string">'/foo/bar'</span>, <span class="string">'./baz'</span>)<span class="comment">// 输出结果为'/foo/bar/baz'</span></span><br><span class="line">path.resolve(<span class="string">'/foo/bar'</span>, <span class="string">'/tmp/file/'</span>)<span class="comment">// 输出结果为'/tmp/file'</span></span><br><span class="line">path.resolve(<span class="string">'wwwroot'</span>, <span class="string">'static_files/png/'</span>, <span class="string">'../gif/image.gif'</span>)<span class="comment">// 当前的工作路径是 /home/itbilu/node，则输出结果为'/home/itbilu/node/wwwroot/static_files/gif/image.gif'</span></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>);<span class="comment">//D:\myProgram\test</span></span><br><span class="line"><span class="keyword">let</span> myPath = path.join(__dirname,<span class="string">'/img/so'</span>);<span class="comment">//D:\myProgram\test\img\so</span></span><br><span class="line"><span class="keyword">let</span> myPath2 = path.join(__dirname,<span class="string">'./img/so'</span>);<span class="comment">//D:\myProgram\test\img\so</span></span><br><span class="line"><span class="keyword">let</span> myPath3 = path.resolve(__dirname,<span class="string">'/img/so'</span>);<span class="comment">//D:\img\so</span></span><br><span class="line"><span class="keyword">let</span> myPath4 = path.resolve(__dirname,<span class="string">'./img/so'</span>);<span class="comment">//D:\myProgram\test\img\so</span></span><br></pre></td></tr></table></figure>
<h4 id="IP"><a href="#IP" class="headerlink" title="IP"></a>IP</h4><p>在<code>package.json</code>的执行脚本中增加<code>--host 0.0.0.0</code>就可以通过ip访问了，缺点是刚开始启动的时候无法打开网页，需要等启动完成后输入地址重新访问。</p>
<p>也可以通过js获取本机ip</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">devServer: &#123;</span><br><span class="line">  disableHostCheck: <span class="literal">true</span>,</span><br><span class="line">  <span class="comment">// host: '0.0.0.0'</span></span><br><span class="line">  host:(<span class="function"><span class="keyword">function</span> <span class="title">getIPAdress</span>(<span class="params"></span>)</span>&#123;  </span><br><span class="line">    <span class="keyword">var</span> interfaces = <span class="built_in">require</span>(<span class="string">'os'</span>).networkInterfaces()  </span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">var</span> devName <span class="keyword">in</span> interfaces)&#123;  </span><br><span class="line">        <span class="keyword">var</span> iface = interfaces[devName]  </span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">var</span> i=<span class="number">0</span>;i&lt;iface.length;i++)&#123;  </span><br><span class="line">            <span class="keyword">var</span> alias = iface[i]</span><br><span class="line">            <span class="keyword">if</span>(alias.family === <span class="string">'IPv4'</span> &amp;&amp; alias.address !== <span class="string">'127.0.0.1'</span> &amp;&amp; !alias.internal)&#123;  </span><br><span class="line">              <span class="keyword">return</span> alias.address  </span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="获取ip.png"></p>
<h2 id="babelrc配置"><a href="#babelrc配置" class="headerlink" title=".babelrc配置"></a>.babelrc配置</h2><p>Babel的配置文件是.babelrc，存放在项目的根目录下。使用 Babel 的第一步，就是配置这个文件。该文件用来设置转码规则和插件，基本格式如下。</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"presets"</span>: [],</span><br><span class="line">  <span class="attr">"plugins"</span>: []</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>presets<br>presets字段设定转码规则，官方提供以下的规则集，你可以根据需要安装。<br>最新转码规则<br>$ npm install –save-dev babel-preset-latest<br>react 转码规则<br>$ npm install –save-dev babel-preset-react<br>不同阶段语法提案的转码规则（共有4个阶段），选装一个<br>Stage 0 - Strawman（展示阶段）<br>Stage 1 - Proposal（征求意见阶段）<br>Stage 2 - Draft（草案阶段）<br>Stage 3 - Candidate（候选人阶段）<br>Stage 4 - Finished（定案阶段）<br>$ npm install –save-dev babel-preset-stage-0<br>$ npm install –save-dev babel-preset-stage-1<br>$ npm install –save-dev babel-preset-stage-2<br>$ npm install –save-dev babel-preset-stage-3</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"presets"</span>: [</span><br><span class="line">    <span class="string">"env"</span>,</span><br><span class="line">    <span class="string">"es2015"</span>,</span><br><span class="line">    <span class="string">"react"</span>,</span><br><span class="line">    <span class="string">"stage-2"</span></span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>如果presets没有设置<code>stage-2</code>，因为这里面有些语法还在<code>stage-2</code>阶段还没有正式发布，所以如果没有加上这个配置就无法解析这种语法。<br><img src="presets没有设置stage-2.png"><br>任何人都可以向标准委员会（又称 TC39 委员会）提案，要求修改语言标准。一种新的语法从提案到变成正式标准，需要经历五个阶段。每个阶段的变动都需要由 TC39 委员会批准。<br>一个提案只要能进入 Stage 2，就差不多肯定会包括在以后的正式标准里面。ECMAScript 当前的所有提案，可以在 TC39 的官方网站Github.com/tc39/ecma262查看。</p>
<p>在SwitchCase的case中如果没有{}<br>当词法声明 (let、const、function 和 class) 出现在 case或default 子句中。该词法声明的变量在整个 switch 语句块中是可见的，但是它只有在运行到它定义的 case 语句时，才会进行初始化操作。为了保证词法声明语句只在当前 case 语句中有效，需要用大括号{}将你子句包裹在块中。</p>
<h3 id="presets"><a href="#presets" class="headerlink" title="presets"></a>presets</h3><p>presets中已经包含了一组用来转换ES6+的语法的插件，如果只使用少数新特性而非大多数新特性，可以不使用preset而只使用对应的转换插件。</p>
<p>babel默认只转换语法（比如箭头函数、解构赋值、class等语法），而不转换新的API（比如Map，Set，Promise），如需使用新的API，还需要使用对应的转换插件或者polyfill。</p>
<p>使用babel-polyfill(不使用useBuiltIns)<br>优点：一次性解决所有兼容性问题,而且是全局的,浏览器的console也可以使用<br>缺点：一次性引入了ES6+的所有polyfill，打包后的js文件体积会偏大，对于现代的浏览器，有些不需要polyfill，造成流量浪费，污染了全局对象，不适合框架或库的开发。</p>
<p>使用babel-preset-env插件和useBuiltIns属性。我的理解是从字面上来看出发点是适配环境的问题，比如支持react的jsx语法，比如支持stage-2的语法（比如…语法），比如支持浏览器版本等跟环境相关的。<br>优点：按需(按照指定的浏览器环境所需)引入polyfill, 一定程度上减少了不必要polyfill的引入。<br>缺点：解决问题的角度不一样，主要是处理环境方面的适配，比如并没办法支持generate语法。</p>
<p>使用babel-plugins。主要用于针对某个特性需要的转义，比如支持写在class的属性transform-class-properties插件。支持import和export的add-module-exports插件。等等<br>优点：配置完一个转换插件后, 代码中每个使用这个API的地方的代码都会被转换成使用polyfill中实现的代码。作用域是模块,避免全局冲突。是按需引入,避免不必要引入造成及代码臃肿。<br>缺点：每个模块内单独引用和定义polyfill函数,造成了重复定义,使代码产生冗余。</p>
<p>使用插件 babel-runtime 与 babel-plugin-tranform-runtime。抽离了公共模块，避免了重复引入，从core.js的库中引入所需polyfill<br>简单来说，就是提供了比较多的通用的公共模块。其实也是一个插件。但是对[].includes(x), 依赖于Array.prototype.include仍无法使用。<br>优点：<br>无全局污染<br>依赖统一按需引入(polyfill是各个模块共享的), 无重复引入, 无多余引入<br>适合用来编写lib(第三方库)类型的代码<br>缺点：<br>被polyfill的对象是临时构造并被import/require的,并不是真正挂载到全局<br>由于不是全局生效, 对于实例化对象的方法,如[].include(x), 依赖于Array.prototype.include仍无法使用。因为这些在转换时并没办法被显示的检查出来。</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"presets"</span>: [</span><br><span class="line">    [<span class="string">"env"</span>,&#123;</span><br><span class="line">      <span class="attr">"modules"</span>: <span class="literal">false</span>,<span class="comment">// 模块化交给webpack处理</span></span><br><span class="line">      <span class="attr">"useBuiltIns"</span>:<span class="string">"usage"</span>,<span class="comment">// "usage" | "entry" | false, defaults to false.</span></span><br><span class="line">      <span class="attr">"targets"</span>: &#123;<span class="attr">"browsers"</span>: [<span class="string">"safari &gt;= 7"</span>, <span class="string">"ie&gt;=8"</span>]&#125;<span class="comment">// 浏览器或者node环境</span></span><br><span class="line">    &#125;],</span><br><span class="line">    <span class="string">"react"</span>,</span><br><span class="line">    <span class="string">"stage-2"</span></span><br><span class="line">  ],</span><br><span class="line">  <span class="attr">"plugins"</span>: [</span><br><span class="line">    <span class="string">"add-module-exports"</span>,<span class="comment">// 转义import和export</span></span><br><span class="line">    <span class="string">"transform-runtime"</span>,<span class="comment">// 转义generator</span></span><br><span class="line">    <span class="string">"transform-decorators-legacy"</span>,<span class="comment">// 转义@</span></span><br><span class="line">    <span class="string">"transform-es3-member-expression-literals"</span>,<span class="comment">// 支持ie</span></span><br><span class="line">    <span class="string">"transform-es3-property-literals"</span>,<span class="comment">// 支持ie</span></span><br><span class="line">    [<span class="string">"transform-es2015-classes"</span>, &#123; <span class="attr">"loose"</span>: <span class="literal">true</span> &#125;],</span><br><span class="line">    <span class="string">"transform-proto-to-assign"</span></span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 是否可以只用useBuiltIns+babel-polyfill不用transform-runtime？不行。一个典型的场景就是前者没有转义generator，后者有对静态的generator做转义。</span></span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">env     useBuiltIns</span><br><span class="line"><span class="literal">false</span>   <span class="number">11165</span>  <span class="number">907</span>KB</span><br><span class="line">usage   <span class="number">8136</span>   <span class="number">674</span>KB</span><br><span class="line">entry   <span class="number">8136</span>   <span class="number">674</span>KB</span><br><span class="line"></span><br><span class="line">transform-runtime</span><br><span class="line"><span class="keyword">default</span> <span class="number">2119</span>   <span class="number">168</span>KB</span><br></pre></td></tr></table></figure>
<h3 id="plugins"><a href="#plugins" class="headerlink" title="plugins"></a>plugins</h3><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"plugins"</span>: [</span><br><span class="line">    <span class="string">"add-module-exports"</span>,<span class="comment">// 转义import和export</span></span><br><span class="line">    <span class="string">"transform-runtime"</span>,<span class="comment">// 转义generator</span></span><br><span class="line">    <span class="string">"transform-decorators-legacy"</span>,<span class="comment">// 转义@</span></span><br><span class="line">    <span class="string">"transform-class-properties"</span>,<span class="comment">// 转义class</span></span><br><span class="line">    <span class="string">"transform-es3-member-expression-literals"</span>,<span class="comment">// 支持ie</span></span><br><span class="line">    <span class="string">"transform-es3-property-literals"</span><span class="comment">// 支持ie</span></span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>配置add-module-exports。作用：支持import和export语法。安装：”babel-plugin-add-module-exports”: “^1.0.0”。</p>
<p>配置transform-runtime。作用：支持generator。当项目启用generate的时候如果没有这个插件会报错regeneratorRuntime is not defined。安装：”babel-plugin-transform-runtime”: “^6.23.0”。</p>
<p>配置transform-decorators-legacy。作用：支持@语法。安装：”babel-plugin-transform-decorators-legacy”: “^1.3.5”</p>
<p>配置transform-class-properties。作用：有时候我们将 defaultProps, propTypes写在class中，而不是写在class外面就可以使用这个插件支持。安装：”babel-plugin-transform-class-properties”: “^6.24.1”。</p>
<p>配置 transform-es3-member-expression-literals和transform-es3-property-literals。作用：兼容IE8。安装：”babel-plugin-transform-es3-member-expression-literals”: “^6.22.0”和”babel-plugin-transform-es3-property-literals”: “^6.22.0”</p>
<p>像下面这种代码</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">_interopRequireDefault</span>(<span class="params">obj</span>) </span>&#123; <span class="keyword">return</span> obj &amp;&amp; obj.__esModule ? obj : &#123; <span class="attr">default</span>: obj &#125;; &#125;</span><br><span class="line"><span class="built_in">module</span>.exports = _main2.default;</span><br></pre></td></tr></table></figure>
<p>在 IE8 下会直接报”缺少标识符、字符串或数字”的错。我们得在对象的属性上加 ‘’ 才可以。就像下面这样：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">_interopRequireDefault</span>(<span class="params">obj</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> obj &amp;&amp; obj.__esModule ? obj : &#123; <span class="string">'default'</span>: obj &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>至于原因，并不是 IE8 下对象的属性必须得加 ‘’ 才行，而是 default 的问题，作为一个关键字，同样的问题还包括 catch。这两种情况，可以通过使用<code>transform-es3-property-literals</code>和<code>transform-es3-member-expression-literals</code>这两个插件搞定。总之，在平时写代码的时候避免使用关键字，或者保留字作为对象的属性值，尤其是在习惯不加引号的情况下。相关讨论：<a href="https://github.com/airbnb/javascript/issues/61" target="_blank" rel="noopener">Allow reserved words for properties</a></p>
<h2 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h2><h3 id="React-Router。Cannot-read-property-‘array’-of-undefined"><a href="#React-Router。Cannot-read-property-‘array’-of-undefined" class="headerlink" title="React Router。Cannot read property ‘array’ of undefined"></a>React Router。Cannot read property ‘array’ of undefined</h3><p>未装propTypes报错Cannot read property ‘array’ of undefined<br>react15之后prop-types被剥离开来，而react-router里面的很多写法还是react.proptypes这样肯定报错。所以有两种方案，一种是把react降到15之前（不包括15），另外一种就是把react-router升级到3.x以上版本。<br>为什么不直接升级到4.x因为我试用了一下发现是服务端渲染，而且一大堆配套的都要升级，因此升级到3.x是最明智的选择。<br><img src="未装propTypes报错1.png"><br><img src="未装propTypes报错2.png"></p>
<h3 id="Babel。Using-removed-Babel-5-option"><a href="#Babel。Using-removed-Babel-5-option" class="headerlink" title="Babel。Using removed Babel 5 option"></a>Babel。Using removed Babel 5 option</h3><p>使用了被移除的babel5中的语法，是因为没有把node_modules排除掉。目录是相对package.json的路径。<br>因为node_modules里面有一些包是用了Babel 5中的语法，但是在这个loader里面又是被移除了，所以就报错了，根本解决办法就是把<code>node_modules</code>exclude掉。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>: &#123;</span><br><span class="line">  rules: [</span><br><span class="line">    &#123;</span><br><span class="line">      exclude:<span class="regexp">/node_modules/</span>,</span><br><span class="line">      test: <span class="regexp">/\.(js|jsx)$/</span>,</span><br><span class="line">      loader: [<span class="string">'babel-loader'</span>,<span class="string">'eslint-loader'</span>]</span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="未exclude导致的babel报错.png"></p>

      
    </div>

    

    
    
    

    

    

    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/blog/tags/前端进阶/" rel="tag"># 前端进阶</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/blog/2018/06/28/blog/thinking-in-form-engine/thinking-in-form-engine/" rel="next" title="Thinking in Form Engine">
                <i class="fa fa-chevron-left"></i> Thinking in Form Engine
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/blog/2022/01/06/blog/dev-ops/dev-ops/" rel="prev" title="DevOps">
                DevOps <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>


  </div>


          </div>
          

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">对美好事物的向往，心中要充满强烈的愿望！</p>
              <p class="site-description motion-element" itemprop="description">沉淀下来的知识，才是真正的财富！</p>
          </div>

          
            <nav class="site-state motion-element">
              
                <div class="site-state-item site-state-posts">
                
                  <a href="/blog/archives/">
                
                    <span class="site-state-item-count">19</span>
                    <span class="site-state-item-name">日志</span>
                  </a>
                </div>
              

              
                
                
                <div class="site-state-item site-state-categories">
                  <a href="/blog/categories/index.html">
                    
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                    <span class="site-state-item-count">22</span>
                    <span class="site-state-item-name">分类</span>
                  </a>
                </div>
              

              
                
                
                <div class="site-state-item site-state-tags">
                  <a href="/blog/tags/index.html">
                    
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                    <span class="site-state-item-count">19</span>
                    <span class="site-state-item-name">标签</span>
                  </a>
                </div>
              
            </nav>
          

          

          

          
          

          
          

          
            
          
          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#前端框架"><span class="nav-number">1.</span> <span class="nav-text">前端框架</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#React生命周期"><span class="nav-number">1.1.</span> <span class="nav-text">React生命周期</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Redux-Saga"><span class="nav-number">1.2.</span> <span class="nav-text">Redux Saga</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Immutable"><span class="nav-number">1.3.</span> <span class="nav-text">Immutable</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#基本规范"><span class="nav-number">1.3.1.</span> <span class="nav-text">基本规范</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#注意事项"><span class="nav-number">1.3.2.</span> <span class="nav-text">注意事项</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Webpack"><span class="nav-number">2.</span> <span class="nav-text">Webpack</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#基本思想"><span class="nav-number">2.1.</span> <span class="nav-text">基本思想</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#Loader"><span class="nav-number">2.1.1.</span> <span class="nav-text">Loader</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#css-loader"><span class="nav-number">2.1.1.1.</span> <span class="nav-text">css-loader</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#style-loader"><span class="nav-number">2.1.1.2.</span> <span class="nav-text">style-loader</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Plugin"><span class="nav-number">2.1.2.</span> <span class="nav-text">Plugin</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#webpack5新特性"><span class="nav-number">2.2.</span> <span class="nav-text">webpack5新特性</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#打包流程"><span class="nav-number">2.3.</span> <span class="nav-text">打包流程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#devtool"><span class="nav-number">2.4.</span> <span class="nav-text">devtool</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#model"><span class="nav-number">2.5.</span> <span class="nav-text">model</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Three-shaking"><span class="nav-number">2.6.</span> <span class="nav-text">Three-shaking</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#基本优化"><span class="nav-number">2.7.</span> <span class="nav-text">基本优化</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#loader和plugin的区别"><span class="nav-number">2.8.</span> <span class="nav-text">loader和plugin的区别</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#loader"><span class="nav-number">2.8.1.</span> <span class="nav-text">loader</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#loader编写原则"><span class="nav-number">2.8.1.1.</span> <span class="nav-text">loader编写原则</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#样式表的Loader-style-loader-css-loader-sass-loader"><span class="nav-number">2.8.1.2.</span> <span class="nav-text">样式表的Loader style-loader css-loader sass-loader</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#file-loader与url-loader"><span class="nav-number">2.8.1.3.</span> <span class="nav-text">file-loader与url-loader</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#plugin"><span class="nav-number">2.8.2.</span> <span class="nav-text">plugin</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#plugin编写原则"><span class="nav-number">2.8.2.1.</span> <span class="nav-text">plugin编写原则</span></a></li></ol></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#补充学习"><span class="nav-number">2.9.</span> <span class="nav-text">补充学习</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#dirname和process-cwd"><span class="nav-number">2.9.1.</span> <span class="nav-text">__dirname和process.cwd()</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#IP"><span class="nav-number">2.9.2.</span> <span class="nav-text">IP</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#babelrc配置"><span class="nav-number">3.</span> <span class="nav-text">.babelrc配置</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#presets"><span class="nav-number">3.1.</span> <span class="nav-text">presets</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#plugins"><span class="nav-number">3.2.</span> <span class="nav-text">plugins</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#常见问题"><span class="nav-number">4.</span> <span class="nav-text">常见问题</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#React-Router。Cannot-read-property-‘array’-of-undefined"><span class="nav-number">4.1.</span> <span class="nav-text">React Router。Cannot read property ‘array’ of undefined</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Babel。Using-removed-Babel-5-option"><span class="nav-number">4.2.</span> <span class="nav-text">Babel。Using removed Babel 5 option</span></a></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright"> &copy; <span itemprop="copyrightYear">2024</span>
  <span class="with-love" id="animate">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">对美好事物的向往，心中要充满强烈的愿望！</span>

  

  
</div>




  <div class="powered-by">由 <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动 v3.9.0</div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">主题 – <a class="theme-link" target="_blank" href="https://theme-next.org">NexT.Gemini</a> v6.4.2</div>




        








        
        <div>
          <a href="https://beian.miit.gov.cn/" target="_blank">闽ICP备15015722号-2</a>
        </div>
      </div>
     
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    
	
    

    
  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>


























  
  
    <script type="text/javascript" src="/blog/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  


  


  <script type="text/javascript" src="/blog/js/src/utils.js?v=6.4.2"></script>

  <script type="text/javascript" src="/blog/js/src/motion.js?v=6.4.2"></script>



  
  


  <script type="text/javascript" src="/blog/js/src/affix.js?v=6.4.2"></script>

  <script type="text/javascript" src="/blog/js/src/schemes/pisces.js?v=6.4.2"></script>



  
  <script type="text/javascript" src="/blog/js/src/scrollspy.js?v=6.4.2"></script>
<script type="text/javascript" src="/blog/js/src/post-details.js?v=6.4.2"></script>



  


  <script type="text/javascript" src="/blog/js/src/bootstrap.js?v=6.4.2"></script>



  



  










  





  

  

  

  

  

  
  

  

  

  

  

  

</body>
</html>
